package ace.tool.generate.code.impl.resolver.impl;

import ace.cmp.data.api.annotation.Index;
import ace.tool.generate.code.impl.resolver.TemplateModelClassResolver;
import ace.tool.generate.code.impl.resolver.model.TemplateModel;
import ace.tool.generate.code.impl.resolver.model.TemplateModelField;
import io.swagger.v3.oas.annotations.media.Schema;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.annotation.Id;

/**
 * @author caspar
 * @date 2023/11/17 10:34
 */
public class TemplateModelDataJdbcClassResolverImpl implements TemplateModelClassResolver {

  @Override
  public TemplateModel resolve(Class value) {
    String modelName = value.getSimpleName();
    String remark = this.resolveModelRemark(value);
    List<TemplateModelField> fields = this.resolveField(value);
    List<Index> indexes = this.resolveEntityClassIndexes(value);
    return TemplateModel.builder()
        .entityClass(value)
        .name(modelName)
        .remark(remark)
        .fields(fields)
        .indexes(indexes)
        .build();
  }

  private String resolveModelRemark(Class value) {
    Schema apiModelAnn = (Schema) value.getAnnotation(Schema.class);
    return Optional.ofNullable(apiModelAnn).map(Schema::description).orElse("");
  }

  private List<TemplateModelField> resolveField(Class value) {

    return Arrays.stream(value.getDeclaredFields())
        .filter(p -> !Modifier.isStatic(p.getModifiers()))
        .filter(p -> !Modifier.isFinal(p.getModifiers()))
        .map(this::resolveField)
        .collect(Collectors.toList());
  }

  private TemplateModelField resolveField(Field field) {
    String name = field.getName();
    Class type = this.resolveFieldType(field);
    String remark = this.resolveFieldRemark(field);
    Boolean idFlag = this.resolveFieldIdFlag(field);
    return TemplateModelField.builder()
        .name(name)
        .type(type)
        .field(field)
        .remark(remark)
        .idFlag(idFlag)
        .build();
  }

  private Boolean resolveFieldIdFlag(Field field) {
    Id idAnn = AnnotatedElementUtils.findMergedAnnotation(field, Id.class);
    return idAnn != null;
  }

  private List<Index> resolveEntityClassIndexes(Class entityClass) {
    Set<Index> indexSet =
        AnnotatedElementUtils.findMergedRepeatableAnnotations(entityClass, Index.class);
    return indexSet.stream().collect(Collectors.toList());
  }

  private String resolveFieldRemark(Field field) {
    Schema apiModelPropertyAnn = field.getAnnotation(Schema.class);
    return Optional.ofNullable(apiModelPropertyAnn)
        .map(
            p -> {
              StringBuilder sb = new StringBuilder();
              sb.append(p.title());
              if (StringUtils.isNotBlank(p.description())) {
                sb.append(" ");
                sb.append(p.description());
              }
              return sb.toString();
            })
        .orElse("");
  }

  private Class resolveFieldType(Field field) {
    return field.getType();
  }
}
